namespace SS.Common.Threading.JobExecutor
{
    #region Used namespaces

    using System;
    using System.Collections.Generic;

    #endregion

    /// <summary>
    /// Reason why the executor reject the request
    /// </summary>
    public enum ExecutorRejectReason
    {
        /// <summary>
        /// The executor is too busy for the new request
        /// </summary>
        TooBusy = 0,

        /// <summary>
        /// The executor is shutting down
        /// </summary>
        ShuttingDown = 1
    }

    /// <summary>
    /// Handler for rejected job (when the excecutor shutting down or fulled)
    /// </summary>
    /// <typeparam name="T">The job type</typeparam>
    /// <param name="executor">The current executor</param>
    /// <param name="job">The job has been rejected</param>
    /// <param name="reason">The reject reason</param>
    public delegate void ExecutorRejectHandler<T>(
        IJobExecutor<T> executor, T job, ExecutorRejectReason reason) where T : IJob;

    /// <summary>
    /// Handler for exception thrown out by the job code
    /// </summary>
    /// <typeparam name="T">The job type</typeparam>
    /// <param name="executor">The current executor</param>
    /// <param name="job">The job that has thrown exception</param>
    /// <param name="exception">Then thrown exception</param>
    public delegate void ExecutorExceptionHandler<T>(
        IJobExecutor<T> executor, T job, Exception exception) where T : IJob;

    /// <summary>
    /// A Job executor
    /// </summary>
    /// <typeparam name="T">The type of jobs those need to be executed</typeparam>
    public interface IJobExecutor<T> : IDisposable
        where T : IJob
    {
        /// <summary>
        /// Initilize the executor
        /// </summary>
        void Initialize();

        /// <summary>
        /// Enqueue a job
        /// </summary>
        /// <param name="job">The job should be done</param>
        void Queue(T job);

        /// <summary>
        /// Stop the executor by signal all workers
        /// </summary>
        /// <param name="force">
        /// Force exit don't wait for remain jobs processed
        /// </param>
        /// <returns>
        /// Remain jobs if force exit
        /// </returns>
        List<T> Stop(bool force);

        /// <summary>
        /// Wait for the executor terminated
        /// </summary>
        /// <param name="millisecondsTimeout">
        /// Timeout in milliseconds
        /// </param>
        /// <returns>
        /// true if the executor terminated
        /// </returns>
        bool WaitForTermination(int millisecondsTimeout);
    }
}
